package com.brokenfunction.util {
	import flash.utils.ByteArray;
	import flash.utils.Endian;
	/*
	 * This class is based on the PCMAudioLibrary
	 * http://www.flashbrighton.org/wordpress/?p=9
	 */
	public class AudioSynth extends ByteArray {
		static public const SAMPLE_RATE_44100:uint = 0x3;
		static public const SAMPLE_RATE_22050:uint = 0x2;
		static public const SAMPLE_RATE_11025:uint = 0x1;
		static public const SAMPLE_RATE_5512_5:uint = 0x0;
		static public const CHANNELS_MONO:uint = 0x0;
		static public const CHANNELS_STEREO:uint = 0x1;
		static public const DEPTH_8BIT:uint = 0x0;
		static public const DEPTH_16BIT:uint = 0x1;
		
		private var isClosed:Boolean = false;
		private const posSwfSize:uint = 4;
		private var posAudioSize:uint;
		private var posSamples:uint;
		private var posStart:uint;
		
		private var _rate:uint;
		private var _depth:uint;
		private var _channels:uint;
		private var _samples:uint = 0;
		
		public function AudioSynth(sampleRate:uint,bitDepth:uint,channls:uint) {
			super();
			_rate = sampleRate & 0x3;
			_depth = bitDepth & 0x1;
			_channels = channls & 0x1;
			
			endian = Endian.LITTLE_ENDIAN;
			writeUnsignedInt(0x09535746); // Magic number + swf version 9
			writeUnsignedInt(0);// swf size (temporary value)
			var i:uint = 0;
			while (i < audioHeaderBytes.length) {
				writeByte(audioHeaderBytes[i++]);
			}
			posAudioSize = position;
			writeUnsignedInt(0);// audio section size (temporary value)
			writeByte(1);// ?
			writeByte(0);// ?
			writeByte(0x30 | (_rate << 2) | (_depth << 1) | _channels);
			posSamples = position;
			writeUnsignedInt(0);// samples (temporary value)
			posStart = position;
		}
		public function close():void {
			if (isClosed) throw new Error("test");
			
			var audioSize:uint = position - posStart;
			var sampleSize:uint = (_channels+1) * (_depth+1);
			_samples = audioSize / sampleSize;
			endian = Endian.LITTLE_ENDIAN;
			
			var pos:uint = position;
			var i:uint = 0;
			while (i < audioFooterBytes.length) {
				writeByte(audioFooterBytes[i++]);
			}
		
			isClosed = true;
		
			position = posSwfSize;
			writeUnsignedInt(position+bytesAvailable);
			
			position = posAudioSize;
			writeUnsignedInt(audioSize + 7);// Why +7?
			
			position = posSamples;
			writeUnsignedInt(_samples);
			
			position = 0;
		}
		public function get bitRate():uint {
			return _rate;
		}
		public function get bitDepth():uint {
			return _depth;
		}
		public function get channels():uint {
			return _channels;
		}
		public function get samples():uint {
			return _samples;
		}
		public override function set position(p:uint):void {
			if (isClosed) {
				super.position = p;
			} else {
				throw new Error("Cannot change position before data is prepared");
			}
		}
		
		
		static private const audioHeaderBytes:Array = [
			0x78 , 0x00 , 0x05 , 0x5F , 0x00 , 0x00 , 0x0F , 0xA0 , 
			0x00 , 0x00 , 0x0C , 0x01 , 0x00 , 0x44 , 0x11 , 0x08 , 
			0x00 , 0x00 , 0x00 , 0x43 , 0x02 , 0xFF , 0xFF , 0xFF , 
			0xBF , 0x15 , 0x0B , 0x00 , 0x00 , 0x00 , 0x01 , 0x00 , 
			0x53 , 0x63 , 0x65 , 0x6E , 0x65 , 0x20 , 0x31 , 0x00 , 
			0x00 , 0xBF , 0x14 , 0xC8 , 0x00 , 0x00 , 0x00 , 0x00 , 
			0x00 , 0x00 , 0x00 , 0x00 , 0x10 , 0x00 , 0x2E , 0x00 , 
			0x00 , 0x00 , 0x00 , 0x08 , 0x0A , 0x53 , 0x6F , 0x75 , 
			0x6E , 0x64 , 0x43 , 0x6C , 0x61 , 0x73 , 0x73 , 0x00 , 
			0x0B , 0x66 , 0x6C , 0x61 , 0x73 , 0x68 , 0x2E , 0x6D , 
			0x65 , 0x64 , 0x69 , 0x61 , 0x05 , 0x53 , 0x6F , 0x75 , 
			0x6E , 0x64 , 0x06 , 0x4F , 0x62 , 0x6A , 0x65 , 0x63 , 
			0x74 , 0x0F , 0x45 , 0x76 , 0x65 , 0x6E , 0x74 , 0x44 , 
			0x69 , 0x73 , 0x70 , 0x61 , 0x74 , 0x63 , 0x68 , 0x65 , 
			0x72 , 0x0C , 0x66 , 0x6C , 0x61 , 0x73 , 0x68 , 0x2E , 
			0x65 , 0x76 , 0x65 , 0x6E , 0x74 , 0x73 , 0x06 , 0x05 , 
			0x01 , 0x16 , 0x02 , 0x16 , 0x03 , 0x18 , 0x01 , 0x16 , 
			0x07 , 0x00 , 0x05 , 0x07 , 0x02 , 0x01 , 0x07 , 0x03 , 
			0x04 , 0x07 , 0x02 , 0x05 , 0x07 , 0x05 , 0x06 , 0x03 , 
			0x00 , 0x00 , 0x02 , 0x00 , 0x00 , 0x00 , 0x02 , 0x00 , 
			0x00 , 0x00 , 0x02 , 0x00 , 0x00 , 0x01 , 0x01 , 0x02 , 
			0x08 , 0x04 , 0x00 , 0x01 , 0x00 , 0x00 , 0x00 , 0x01 , 
			0x02 , 0x01 , 0x01 , 0x04 , 0x01 , 0x00 , 0x03 , 0x00 , 
			0x01 , 0x01 , 0x05 , 0x06 , 0x03 , 0xD0 , 0x30 , 0x47 , 
			0x00 , 0x00 , 0x01 , 0x01 , 0x01 , 0x06 , 0x07 , 0x06 , 
			0xD0 , 0x30 , 0xD0 , 0x49 , 0x00 , 0x47 , 0x00 , 0x00 , 
			0x02 , 0x02 , 0x01 , 0x01 , 0x05 , 0x1F , 0xD0 , 0x30 , 
			0x65 , 0x00 , 0x5D , 0x03 , 0x66 , 0x03 , 0x30 , 0x5D , 
			0x04 , 0x66 , 0x04 , 0x30 , 0x5D , 0x02 , 0x66 , 0x02 , 
			0x30 , 0x5D , 0x02 , 0x66 , 0x02 , 0x58 , 0x00 , 0x1D , 
			0x1D , 0x1D , 0x68 , 0x01 , 0x47 , 0x00 , 0x00 , 0xBF , 
			0x03 
		];
		static private const audioFooterBytes:Array = [
			0x3F , 0x13 , 0x0F , 0x00 , 0x00 , 0x00 , 0x01 , 0x00 , 
			0x01 , 0x00 , 0x53 , 0x6F , 0x75 , 0x6E , 0x64 , 0x43 , 
			0x6C , 0x61 , 0x73 , 0x73 , 0x00 , 0x44 , 0x0B , 0x0F , 
			0x00 , 0x00 , 0x00 , 0x40 , 0x00 , 0x00 , 0x00 
		];
	}
}